You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

83 lines
2.4 KiB

import multer from "multer";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { callNodeListener } from "h3";
import { POST_MEDIA_PUBLIC_PREFIX } from "#server/constants/media";
import { replaceMediaAssetFileFromTempUpload } from "#server/service/media";
import { R } from "#server/utils/response";
type MulterUploadedFile = {
originalname: string;
filename: string;
path: string;
mimetype: string;
size: number;
};
export default defineWrappedResponseHandler(async (event) => {
const user = await event.context.auth.requireUser();
const idRaw = getRouterParam(event, "id");
const assetId = Number(idRaw);
if (!Number.isInteger(assetId) || assetId < 1) {
throw createError({ statusCode: 400, statusMessage: "无效的资源 id" });
}
const upload = multer({
storage: multer.diskStorage({
destination: (_req, _file, cb) => {
cb(null, os.tmpdir());
},
filename: (_req, file, cb) => {
const ext = path.extname(file.originalname).toLowerCase();
const baseName = path.basename(file.originalname, ext).replace(/[^a-z0-9]/gi, "-");
cb(null, `reupload-${Date.now()}-${Math.round(Math.random() * 1e9)}-${baseName}${ext}`);
},
}),
limits: { fileSize: 10 * 1024 * 1024 },
fileFilter: (_req, file, cb) => {
const allowed = ["image/png", "image/jpeg", "image/jpg", "image/webp"];
if (allowed.includes(file.mimetype)) {
cb(null, true);
} else {
cb(new Error("只支持 PNG/JPG/WebP 格式图片"));
}
},
});
await callNodeListener(
// @ts-expect-error multer 中间件类型
upload.single("file"),
event.node.req,
event.node.res,
);
// @ts-expect-error multer 挂载 file
const file = event.node.req.file as MulterUploadedFile | undefined;
if (!file?.path) {
throw createError({ statusCode: 400, statusMessage: "请选择要上传的图片" });
}
try {
const result = await replaceMediaAssetFileFromTempUpload({
assetId,
actorUserId: user.id,
actorIsAdmin: false,
tempInputPath: file.path,
});
return R.success({
url: `${POST_MEDIA_PUBLIC_PREFIX}${result.storageKey}`,
sizeBytes: result.sizeBytes,
});
} catch (err) {
if (file.path && fs.existsSync(file.path)) {
try {
fs.unlinkSync(file.path);
} catch {
/* ignore */
}
}
throw err;
}
});